#include "ini.h"
#include "rss.h"
#include "email.h"
#include "task.h"
#include "download_file.h"
#include "tests.h"
#include "date.h"
#include "utilities.h"
#include <stdio.h>
#include <stdlib.h>

///////////////////////////////////////////////////////////////////////////////

// #define FILE_TRACE

#include "file_trace.h"

///////////////////////////////////////////////////////////////////////////////

//------------------------------------------------------------------------------
// defines
//------------------------------------------------------------------------------

#define MAX_FEED_URL_LENGTH 1024
#define DUMP_FORMATTED_DIGEST

//------------------------------------------------------------------------------
// static functions
//------------------------------------------------------------------------------

static void
s_DumpFeeds()
{
    const char** urls = INI_FeedSources();
    int  count_feeds = INI_FeedCount();
    int i;

    printf("\n\nfeeds\n");
    for (i = 0; i < count_feeds; i++)
    {
        printf("    feed[%d]:|%s|\n", i, urls[i]);
    }
}

static void
s_DumpCustomers()
{
    const customer_t*  customers = INI_Customers();
    int  count_customers = INI_CustomerCount();
    int i;
    int j;

    printf("\n\ncustomers\n");
    for (i = 0; i < count_customers; i++)
    {
        printf("    customers[%d]\n"
               "        name         :|%s|\n"
               "        surname      :|%s|\n"
               "        email        :|%s|\n"
               "        digest option:|%s|\n"
               "        format option:|%s|\n"
               "        time zone    :|%s|\n"
               "        keywords     :|",
               i,
               customers[i].name,
               customers[i].surname,
               customers[i].email,
			   (customers[i].digest_opt == digest_opt_title ? "Title" : "Title+Desc"),
			   (customers[i].format_opt == format_opt_text ? "Text" : "HTML"),
               customers[i].time_zone
               );

        // dump the keywords of the customer
        for (j = 0; ;)
        {
            printf((customers[i].keywords)[j]);

            // should continue?
            if (customers[i].keywords[++j] != NULL)
                printf(", ");
            else
                break;
        }

        // done
        printf("|\n\n");
    }
}

static void
s_DumpDigests()
{
    const customer_t*  customers = INI_Customers();
    int  count_customers = INI_CustomerCount();
	int  customer;
	int  keyword;
	int  item;

    printf("\n\ndigests\n");

    for (customer = 0; customer < count_customers; customer++)
    {
        for (keyword = 0; customers[customer].keywords[keyword] != NULL; keyword++)
        { 
            printf("    customer[%d]:|%s %s|  keyword[%d]:|%s|\n",
                   customer,
                   customers[customer].name,
                   customers[customer].surname,
                   keyword,
                   customers[customer].keywords[keyword]);

			if (customers[customer].raw_digest[keyword] == NULL)
			{
				printf("        no item found!\n\n");
			}
			else
			{
				// first count the digest items for the customer
				for (item = 0; customers[customer].raw_digest[keyword][item] != NULL; item++)
					;

				printf("        |%d| item%s found\n\n", item, (item > 1 ? "s" : ""));

				// next dump the digest items one-by-one
				for (item = 0; customers[customer].raw_digest[keyword][item] != NULL; item++)
				{
					printf("            digest item[%d]\n"
                           "                 title:|%s|\n"
                           "                  desc:|%s|\n"
						   "                  link:|%s|\n"
						   "               pubdate:|%s|\n\n", 
						   item,
						   customers[customer].raw_digest[keyword][item]->title,
						   customers[customer].raw_digest[keyword][item]->description,
						   customers[customer].raw_digest[keyword][item]->url,
						   customers[customer].raw_digest[keyword][item]->pubdate);
				} // for item
			}
		} // for keyword
	} // for customer
}

static bool
s_FormatDigests()
{
    const customer_t*  customers = INI_Customers();
    int  count_customers = INI_CustomerCount();
	int  customer;
    bool result = false;

    for (customer = 0; customer < count_customers; customer++)
    {
		switch (customers[customer].format_opt)
		{
			case format_opt_html:
				if (RSS_HTMLFormatDigest(customer) == false)
					goto exit;

				break;

			case format_opt_text:
				if (RSS_TextFormatDigest(customer) == false)
					goto exit;

				break;
		}

#ifdef DUMP_FORMATTED_DIGEST
		printf("formatted digest for |%s %s|\n\n%s\n", 			  
				customers[customer].name,
				customers[customer].surname,
				customers[customer].formatted_digest);
#endif
	}

    result = true;

exit:

    return result;
}

static void
s_DeleteStatisticsFile()
{
    char * path = RSS_GetStatisticsFilePath();
    
    remove(path);

    free(path);
}

static void
s_SendStatistics()
{
    const char* ini_path = INI_GetIniPath();
    char time_buffer[32];
    time_t current_time;
    time_t last_report_time;
    struct tm * current_time_struct_ptr;
    struct tm * last_report_time_struct_ptr;
    DWORD char_count;
    int last_report_yday;
    int last_report_year;
    bool is_same_day = false;
    BOOL write_result;

    current_time = time(NULL);

    if (DATE_GetDayOfMonth(current_time) != DAY_OF_MONTH_FOR_SENDING_STATISTICS_LOG)
    {
        F_PRINT(("It is not the day of the month for reporting statistics."));
        return;
	}

    // read last report time
    char_count = GetPrivateProfileString(INI_STATISTICS_SECTION_NAME, INI_STATISTICS_KEY_NAME,
        NULL, time_buffer, sizeof(time_buffer), ini_path);

    if (char_count == 0)
    {
        // this is not a fatal error; may be the first run
        F_PRINT(("Failed to read last report time.\n"));
    }
    else
    {
        // convert read time to stuct tm, making sure to user a 64-bit number
        last_report_time = (time_t)_strtoi64(time_buffer, NULL, 10);
        last_report_time_struct_ptr = localtime(&last_report_time);

        // save last report year day and year before extracting the same
        // for the current time, which will overwrite these values
        last_report_yday = last_report_time_struct_ptr->tm_yday;
        last_report_year = last_report_time_struct_ptr->tm_year;

        current_time_struct_ptr = localtime(&current_time);

        is_same_day = (current_time_struct_ptr->tm_yday == last_report_yday) &&
            (current_time_struct_ptr->tm_year == last_report_year);

        if (is_same_day)
        {
            // no need to do anything
            return;
        }
    }

    // make sure the year day and year are the same before sending the statistics
    if (EMAIL_SendStatistics(INI_CustomerCount(), INI_Customers()) == false)
    {
        // this is not a fatal error
        F_ERROR(("Sending statistics failed.\n"));
    }
    else
    {
        // now that statistics have been sent, reset them
        s_DeleteStatisticsFile();

        // store last report time in the ini file in time_t format
        sprintf(time_buffer, "%lld", current_time);

        write_result = WritePrivateProfileString(INI_STATISTICS_SECTION_NAME, 
            INI_STATISTICS_KEY_NAME, time_buffer, ini_path);
        if (write_result == FALSE)
        {
            // this is not a fatal error
            F_ERROR(("Failed to store last statistics report time.\n"));
        }
    }
}

int main(int argc, char** argv)
{
	char*  ini_path = NULL;
	bool  run_tests = false;
	int  i;

    srand((unsigned int)time(0)); // needed since rand() is called to randomize various parts of emails

	// process the command line args if any
	F_PRINT(("argv[0]:|%s|\n", argv[0]));
	for (i = 1; i < argc; i++)
	{
		F_PRINT(("argv[%d]:|%s|\n", i, argv[i]));

		if (strcmp(argv[i], "--test") == 0)
		{
			run_tests = true;
		}
		else if (strcmp(argv[i], "--inipath") == 0)
		{
			// next cmdline option specifies the "ini path"
			ini_path = argv[++i];
		}
		else
		{
			F_ERROR(("Unknown command line option |%s| ignored...\n", argv[i]));
		}
	}

    // inits
    if (INI_Init(ini_path) == false)
    {
        F_ERROR(("ini read failed!\n"));

        return EXIT_FAILURE;
    }

    if (DATE_Init() == false)
    {
        F_ERROR(("date init failed!\n"));

        return EXIT_FAILURE;
    }

    if (RSS_Init(INI_FeedSources(),
                 INI_FeedCount(),
				 INI_Customers(),
                 INI_CustomerCount()) == false)
    {
        F_ERROR(("rss init failed!\n"));

        return EXIT_FAILURE;
    }

    // dump the input data
    s_DumpFeeds();
    s_DumpCustomers();
	
    // download the feeds from internet
    if (RSS_DownloadFeeds() == false)
    {
        F_ERROR(("download feeds failed!\n"));
        return EXIT_FAILURE;
    }

	// sort the feeds
	RSS_SortFeedsbyDate();

    // create the digests per customer
    if (RSS_CreateDigests() == false)
    {
        F_ERROR(("create digests failed!\n"));
        return EXIT_FAILURE;
    }

	// format the digests per customer
	if (s_FormatDigests() == false)
    {
        F_ERROR(("format digests failed!\n"));
        return EXIT_FAILURE;
    }

	// send the statistics
    RSS_LogStatistics();
    s_SendStatistics();

    // send the digests
    if (EMAIL_SendDigests(INI_CustomerCount(), INI_Customers()) == false)
    {
        F_ERROR(("Sending digests failed!\n"));
        return EXIT_FAILURE;
    }

    // schedule run time
    TASK_Schedule(INI_TaskSchedule());

    EMAIL_ExtractCommandData();
	
    // deinits
    INI_Free();
	DATE_Free();
    RSS_Free();

    // should run the tests?
	if (run_tests && run_all_tests() != CUE_SUCCESS)
	{
		return EXIT_FAILURE;
	}

    return EXIT_SUCCESS;
}
